package com.goldsprite.microhorigame.screens.games;

import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.graphics.glutils.*;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.math.*;
import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.viewport.*;
import com.goldsprite.gameframeworks.assets.*;
import com.goldsprite.gameframeworks.ecs.SpriteUtils;
import com.goldsprite.gameframeworks.ecs.component.*;
import com.goldsprite.gameframeworks.ecs.entity.*;
import com.goldsprite.gameframeworks.ecs.system.*;
import com.goldsprite.gameframeworks.input.*;
import com.goldsprite.gameframeworks.log.*;
import com.goldsprite.gameframeworks.rhino.*;
import com.goldsprite.gameframeworks.screens.*;
import com.goldsprite.gameframeworks.tiledmap.MapManager;
import com.goldsprite.gameframeworks.timeline.TimeLineTask;
import com.goldsprite.gameframeworks.utils.*;
import com.goldsprite.microhorigame.ecs.*;
import com.goldsprite.microhorigame.ecs.fsms.states.*;
import com.goldsprite.microhorigame.systems.*;

import com.goldsprite.gameframeworks.utils.math.Vector2;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

public class MainGameScreen extends GScreen {
	public static Options options = new Options();
	Stage uiStage;
	SpriteBatch batch;
	ShapeRenderer shapeRenderer;
	int worldViewWidth = 960, worldViewHeight = 540;
	int uiViewWidth = 960, uiViewHeight = 540;
	private FitViewport worldViewport, uiViewport;
	private OrthographicCamera worldCamera, uiCamera;
	private GameSystem gm;
	private GObject spawnPoint;
	private GObject player;
	private float[] nextCamZoom = {0};

	@Override
	public void create() {
		batch = new SpriteBatch();
		shapeRenderer = new ShapeRenderer();

		init();

		createUI();

		//相机缩放操作
		getImp().addProcessor(CameraTool.createCamZoomEvent(worldCamera, uiStage, nextCamZoom));

		createGM();

//		createTmx();

		createGObjects();
	}

	private void init() {
		worldCamera = new OrthographicCamera();
		worldViewport = new FitViewport(worldViewWidth, worldViewHeight, worldCamera);
		worldCamera.setToOrtho(false, worldViewWidth, worldViewHeight);
		worldCamera.position.set(worldViewWidth / 2f, worldViewHeight / 2f, 0);
		worldCamera.update();

		uiCamera = new OrthographicCamera();
		uiViewport = new FitViewport(uiViewWidth, uiViewHeight, uiCamera);
		uiCamera.setToOrtho(false, uiViewWidth, uiViewHeight);
		uiCamera.position.set(uiViewWidth / 2f, uiViewHeight / 2f, 0);
		uiCamera.update();

		nextCamZoom[0] = worldCamera.zoom = options.camZoom;//0.65f
	}

	private void createUI() {
		uiStage = new Stage(getViewport());
	}

	private void createGM() {
		// 然后初始化游戏系统 这会自动创建并注册SpriteRenderer和PhysicsSystem
		gm = new GameSystem(worldViewport, uiViewport);

		gm.onWake.add(o -> CoreTestRhino.test3());

		GameSystem.gizmos.setEnabled(options.enableGizmos);
	}

	private String tmxPath = "tmx/main.tmx";
	private MapManager mapManager;
	private TiledMap map;
	// 地图缩放比例
	private float unitScale = 1 / 8f * 8f * 1f;

	private void createTmx() {
		// 加载TMX地图文件
//		map = new TmxMapLoader().load(tmxPath);
		mapManager = new MapManager();
		mapManager.loadMap(tmxPath);
		map = mapManager.tiledMap;

		//解析并实例化碰撞框
		Array<Rectangle> collRects = mapManager.getCollisionRects();
		for (Rectangle rec : collRects) {
			float x = rec.x * unitScale;
			float y = rec.y * unitScale;
			float width = rec.width * unitScale;
			float height = rec.height * unitScale;
			GObject wallBox = GObjectGenerator.newWall(x + width / 2f, y + height / 2f, width, height, false);
		}

		//解析并实例化GObject对象
		MapLayer gobjectLayer = map.getLayers().get("GObjects");
		for (MapObject mapObj : gobjectLayer.getObjects()) {
			String objectClazz = mapObj.getProperties().get("type", String.class);
			float x = mapObj.getProperties().get("x", Float.class) * unitScale;
			float y = mapObj.getProperties().get("y", Float.class) * unitScale;
			if ("Campfire".equals(objectClazz)) {
				float healAmount = mapObj.getProperties().get("healAmount", Float.class);
				GObjectGenerator.setObjScale(unitScale);
				GObjectGenerator.newCampfire(x, y, healAmount);
			} else if ("MonsterPortal".equals(objectClazz)) {
				String type = mapObj.getProperties().get("monsterType", String.class);
				MonsterType monsterType = MonsterType.valueOf(type);
				GObjectGenerator.setObjScale(unitScale);
				GObjectGenerator.newMonsterPortal(x, y, monsterType);
			}
			//加载玩家重生点
			else if ("SpawnPoint".equals(objectClazz) && options.useTmxMapSpawnPoint) {
				options.playerSpawnPoint.set(x, y);
			}
		}

		//实例化瓦片地图系统
		GObject tiledMapObj = new GObject() {{
			setName("TiledMapGObject");
			setTransform();
		}};
		TiledMapComponent tiledMapComp = tiledMapObj.addComponent(new TiledMapComponent());
		tiledMapComp.setSpriteLayer("Background");
		tiledMapComp.init(map, unitScale);

	}

	Vector2 playerPos = new Vector2();

	private void createGObjects() {
		float width, height;
//		GObjectGenerator.newGround(480, 50, 5000, 75);
		width = 40;
		height = 75;
//		GObjectGenerator.newGround(50 - width, 80 + height / 2f, width, height);

		createSpawnPoint(options.playerSpawnPoint.x, options.playerSpawnPoint.y);

		createParallaxBackground();//依赖重生点位置, 依赖playerPos

		createPlayerCharacter();//依赖重生点位置

		//createCloudLayer();

		GObjectGenerator.newGlow(300, 120);
//		GObjectGenerator.newMonsterDoor(380, 83);
//		GObjectGenerator.newCamp1(700, 87.5f-1);

//		GObjectGenerator.newGolem(450, 124);
		GObjectGenerator.newBlackCanine(540, 124);
//		GObjectGenerator.newDemonRat(620, 124);

		//test
		GObjectGenerator.newDemonRat(620 - 8, 124 + 36);
		AtomicReference<GObject> platform = new AtomicReference<>();
		final float horiVel = 20;
		GameSystem.timeLineTaskSystem.executeTimeLineTask(TimeLineTask.sequence(
			e -> {
				platform.set(GObjectGenerator.newPlatform(GameRes.Blue, 620 + 50, 124 + 6, 40, 15));
				platform.get().awake();
			}
			,
			e -> e.isCompleted = RigidbodyComponent.moveTo(platform.get(), 620 + 50 + 50, 124 + 6, horiVel, 0),
			e -> e.wait(2f),
			e -> e.isCompleted = RigidbodyComponent.moveTo(platform.get(), 620 + 50, 124 + 6, horiVel, 0),
			e -> e.wait(2f),
			e -> e.again(1)
		));
	}

	//与相机位置恒定的世界云层，永远固定于相机上方滚动
	private void createCloudLayer() {
		GObject worldCloudLayer = new GObject() {{
			setName("WorldCloudLayer");
			setTransform();
		}};
		worldCloudLayer.transform.position.set(200, 300);

		WorldCloudComponent cloudComp = worldCloudLayer.addComponent(WorldCloudComponent.class);
		cloudComp.setSpriteLayer("MiddleBackground");
		cloudComp.setPivot(Pivot.Center);
		cloudComp.getScale().set(1f);
	}

	private void createParallaxBackground() {
		GObject back = new GObject() {{
			setName("Back");
			setTransform();
		}};
		back.transform.position.set(0, 0);

		ParallaxBackgroundComponent parallaxBg = back.addComponent(ParallaxBackgroundComponent.class);

//        // 从资源添加多个图层
//        float[] parallaxFactors = {0f, 0.4f, 0.6f, 0.8f}; // 越远的图层移动越慢
//        parallaxBg.addLayersFromResource(GameRes.Background_Forest, 0, 4, parallaxFactors);

//		GameRes res = GameRes.Background_Forest;
		GameRes res = GameRes.Background_MountainPlains;
		SpriteUtils.setUVUnit(res.getUVUnit());
		Array<TextureRegion> regions = SpriteUtils.splitAllFrames(res, 4, 1, 4);

		OrthographicCamera cam = GameSystem.worldCamera;
		float regionWidth = res.getUVUnit()[0];
		float regionHeight = res.getUVUnit()[1];
		//Vector2 startPos = new Vector2(-(cam.viewportWidth + regionWidth*0)/2f, -(cam.viewportHeight + regionHeight*0)/2f);
		float scl = 1f;
		Vector2 startPos = Vector2.obtain(0, regionHeight * scl * 0.3f - cam.viewportHeight / 2f * 0).add(options.playerSpawnPoint);
		Vector2 tmp = Vector2.obtain();
//		float[] factors = {
//			1.0f,  0f,
//			0.9f,  0f,
//			0.8f,  0f,
//			0.67f, 0f,
//			0.5f,  0f,
//			1.0f,  0f,
//		};
		float[] factors = {
			0.9f, 0f,
			0.8f, 0f,
			0.7f, 0f,
			0.6f, 0f,
		};
		for (int i = 0; i < factors.length / 2 && i < regions.size; i++) {
			float facX = factors[i * 2 + 0];
			float facY = factors[i * 2 + 1];
			parallaxBg.addMultiLayer(3, regions.get(i), new Vector2(tmp.set(facX, facY)), new Vector2(startPos), scl);
		}
		//parallaxBg.addMultiLayer(3, regions.get(1), new Vector2(0.2f, 0), new Vector2(startPos), 1);

		// 设置跟随相机
		parallaxBg.setFollowTarget(GameSystem.worldCamera.position);
		parallaxBg.setCamStartPos(spawnPoint.getTransform().getPosition());
		//parallaxBg.setFollowTargetByEntity(playerPos);
	}

	private void createSpawnPoint(float x, float y) {
		spawnPoint = new GObject().setTransform().setName("Spawn Point");
		spawnPoint.transform.position.set(x, y);

		SpriteComponent sprite = spawnPoint.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("MiddleBackground");
		sprite.setPivot(Pivot.LeftDown);
		sprite.setRegion(GameRes.SpawnPoint);
		sprite.setOriginOffset(GameRes.SpawnPoint.getUVUnit()[0] / 2f, 12);
		sprite.getScale().set(0.5f);
	}


	private void createEntity(String name, float x, float y, String layer, float scale, Color color) {
		GObject entity = new GObject().setTransform().setName(name);
		TransformComponent transform = entity.addComponent(TransformComponent.class);
		transform.position.set(x, y);

		SpriteComponent sprite = entity.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("Entity");
		sprite.setRegion(GameRes.Boss_Sample);
		sprite.setScale(scale, scale);
		sprite.setSpriteLayer(layer);
		sprite.setColor(color);
	}


	private void createPlayerCharacter() {
		Vector2 spawnPos = options.playerSpawnPoint;
		GameRes res = GameRes.Frost;
		float playerScl = 1.0f;
		Vector2 bodySize = res.bodySize;

		player = new GObject().setTransform().setName("Frost");
		player.setTag("Player");
		Debug.logT("PlayerInfo", "玩家创建, 玩家名: %s, Tag: %s", player.getName(), player.getTag());
		player.transform.position = playerPos;
		player.transform.position.set(spawnPos.x, spawnPos.y);

		RigidbodyComponent rigi = player.addComponent(RigidbodyComponent.class);
		rigi.setBodyType(BodyType.DYNAMIC);
		rigi.setGravityScale(4.0f); // 更强的重力

		RectColliderComponent bodyColl = player.addComponent(RectColliderComponent.class);
//		bodyColl.setEnable(false);
		bodyColl.setName("BodyColl");
		bodyColl.setTag("bodyColl");
		bodyColl.setLayerName("Player");
		bodyColl.setSize(bodySize.x * playerScl, bodySize.y * 0.75f * playerScl);
		bodyColl.setOffset(0, bodySize.y / 2f * playerScl * 0.94f);

		FootTriggerComponent footTrigger = player.addComponent(FootTriggerComponent.class);
		footTrigger.setEnable(false);
		footTrigger.setName("FootTrigger");
		footTrigger.setLayerName("Player");
		footTrigger.setRadius(bodySize.x / 2f * playerScl * 1.0f);
		footTrigger.setOffset(0, playerScl * 2.5f);
		footTrigger.setBodyColl(bodyColl);

		float atkSizeX = (123 - 43) * playerScl;
		float atkSizeY = 24 * playerScl;
		RectColliderComponent atkTrigger = player.addComponent(RectColliderComponent.class);
		atkTrigger.setName("FlippableAtkTrigger");
		atkTrigger.setLayerName("Attacker");
		atkTrigger.setTrigger(true);
		atkTrigger.setEnable(false);
		atkTrigger.setSize(atkSizeX, atkSizeY);
		atkTrigger.setOffset(-(74 - 43) * playerScl + atkSizeX / 2f, atkSizeY / 2f);
		Consumer<ColliderComponent> atkEvent = other -> {
			EntityFsmComponent victimFsm = other.getComponent(EntityFsmComponent.class);
			if (victimFsm != null) {
				EntityFsmComponent selfFsm = player.getComponent(EntityFsmComponent.class);
				float damage = selfFsm.getProps().getDamage();
				Debug.logT("AttackTrigger", "%s的攻击器攻击到: %s, 伤害: %s", player.getName(), victimFsm.getName(), damage);
				victimFsm.trigHurt(damage);
			}
		};
		atkTrigger.onTriggerEnterEvent.add(atkEvent);

		SpriteComponent sprite = player.addComponent(SpriteComponent.class);
		sprite.setSpriteLayer("Player");
		sprite.setPivot(Pivot.LeftDown);
		sprite.setOriginOffset(117, 16);
		sprite.getScale().set(playerScl);
		sprite.setColor(Color.WHITE);

		AnimatorComponent animator = player.addComponent(AnimatorComponent.class);
		SpriteUtils.setUVUnit(res.getUVUnit());
		animator.addAnim("Idle", new Animation<>(.15f, SpriteUtils.splitFrames(res, 0, 6), Animation.PlayMode.LOOP));
		animator.addAnim("Move", new Animation<>(.28f, SpriteUtils.splitFrames(res, 1, 3), Animation.PlayMode.LOOP));
		animator.addAnim("Hurt", new Animation<>(.1f, SpriteUtils.splitFrames(res, 2, 2), Animation.PlayMode.NORMAL));
		animator.addAnim("Attack", new Animation<>(.12f, SpriteUtils.splitFrames(res, 3, 7), Animation.PlayMode.NORMAL));
		animator.addAnim("Attack2", new Animation<>(.1f, SpriteUtils.splitFrames(res, 4, 5), Animation.PlayMode.NORMAL));
		animator.addAnim("Jump", new Animation<>(.15f, SpriteUtils.splitFrames(res, 6, 4), Animation.PlayMode.LOOP));
		animator.addAnim("Fall", new Animation<>(.15f, SpriteUtils.splitFrames(res, 7, 4), Animation.PlayMode.LOOP));
		animator.addAnim("Death", new Animation<>(.15f, SpriteUtils.splitFrames(res, 8, 9), Animation.PlayMode.NORMAL));

		EntityInputComponent input = player.addComponent(EntityInputComponent.class);
		input.setEnableUserInput(true);

		EntityPropsComponent props = player.addComponent(EntityPropsComponent.class);

		EntityFsmComponent fsm = player.addComponent(EntityFsmComponent.class);
		fsm.setName("Player");
		fsm.setBodyCollider(bodyColl);
		fsm.setAttackTrigger(atkTrigger);
		fsm.setFootTrigger(footTrigger);
		fsm.onInitializeStates(() -> {
			fsm.addState(new EntityIdleState(), 0);
			fsm.addState(new EntityMoveState(), 1);
			fsm.addState(new EntityJumpState(), 2);
			fsm.addState(new EntityFallState(), 2);
			fsm.addState(new EntityContinuousAttackState()
				.setAnimNames("Attack", "Attack2")
				.setAttackFrames(3, 2), 3);
			fsm.addState(new EntityHurtState(), 4);
			fsm.addState(new EntityDeathState().noDestory(), 5);
		});

		FollowCamComponent followCamComp = player.addComponent(FollowCamComponent.class);
		followCamComp.setCamZoomRect(options.camZoomRect);
	}

	@Override
	public void render0(float delta) {
		logic(delta);

		worldViewport.apply();
		uiViewport.apply();

		gm.gameLoop(delta);

//		if (GameSystem.drawGizmos)
//			renderPhysicsDebug();
	}

	private void logic(float delta) {
		Debug.infoT("PlayerInfo", "玩家位置: %s", player.transform.position);

		//临时y移动
		Vector2 moveDir = GameInputSystem.getInstance().getInputAction("Move").readValue();
		float yVel = player.getComponent(EntityPropsComponent.class).getOriSpeed();
		RigidbodyComponent rigi = player.getComponent(RigidbodyComponent.class);
		rigi.setVelocity(rigi.getVelocity().x, moveDir.y * yVel);

		//相机缩放
		float zoom = worldCamera.zoom;
		float interpolation = delta * 3f;
//		interpolation = 1;//取消插值
		zoom = MathUtils.lerp(zoom, nextCamZoom[0], interpolation);//插值
		zoom = MathUtils.clamp(zoom, options.camZoomRect[4], options.camZoomRect[5]);//限制
		worldCamera.zoom = zoom;//更新
	}

	private void renderPhysicsDebug() {
		// 获取物理系统并渲染调试信息
		PhysicsSystem physicsSystem = GameSystem.getSystem(PhysicsSystem.class);
		if (physicsSystem != null && physicsSystem.isDebugRenderEnabled()) {
			// 设置世界相机的投影矩阵
			shapeRenderer.setProjectionMatrix(worldCamera.combined);
			physicsSystem.renderDebug(shapeRenderer, worldCamera);
		}
	}

	@Override
	public void resize(int width, int height) {
		worldViewport.update(width, height, true);
		uiViewport.update(width, height, true);
	}

	@Override
	public void show() {
		super.show();
		GameInputSystem.showAndroidKeyBoard(true);
	}

	@Override
	public void hide() {
		super.hide();
		GameInputSystem.showAndroidKeyBoard(false);
	}

	public static class Options {
		public boolean showIntros = false;

		public boolean enableGizmos = true;

		public boolean useTmxMapSpawnPoint = false;//使用地图数据出生点坐标
		//		public Vector2 playerSpawnPoint = new Vector2(150, 84);//地图左边缘出生点
		//public Vector2 playerSpawnPoint = new Vector2(532.8f, 97.1f);//碰撞测试点2
		public Vector2 playerSpawnPoint = new Vector2(532.8f, 100f);//碰撞测试点4
//		public Vector2 playerSpawnPoint = new Vector2(370, 84);//怪物旁
		public float playerFallDeathHigh = -400;

		//				public float camZoom = 0.38f * 5f;//越大 人物越小
		public float camZoom = 0.3f;//越大 人物越小

		public boolean fightMode = false;//是否出怪
		public boolean playBgm = false;//是否播放bgm
		//		public float[] camZoomRect = new float[] { 80 + 540, 960, 90, 540, 0.3f, 1.2f*10 };//相机限制左x右x, 下y上y
//public float[] camZoomRect = new float[] { 400, 3600, 540,  1300, 0.3f, 1.2f };//相机限制左x右x, 下y上y
		public float[] camZoomRect = new float[]{-9999, 9999, -9999, 9999, 0.1f, 1.2f * 10};//相机限制左x右x, 下y上y
	}

}
